package io.renren.service.impl;

import io.renren.common.exception.RRException;
import io.renren.common.utils.ConfigConstant;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.DecimalUtils;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.ProjectConstant;
import io.renren.common.utils.Query;
import io.renren.common.validator.Assert;
import io.renren.dao.MemberMachineDao;
import io.renren.entity.BalanceDetailEntity;
import io.renren.entity.MachineEntity;
import io.renren.entity.MemberEntity;
import io.renren.entity.MemberMachineEntity;
import io.renren.service.BalanceDetailService;
import io.renren.service.MachineService;
import io.renren.service.MemberMachineService;
import io.renren.service.MemberService;
import io.renren.service.SysConfigService;

import java.util.Date;
import java.util.Map;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;

@Service("memberMachineService")
public class MemberMachineServiceImpl extends ServiceImpl<MemberMachineDao, MemberMachineEntity> implements MemberMachineService {

	@Autowired
	MemberService memberService;

	@Autowired
	MachineService machineService;

	@Autowired
	BalanceDetailService balanceDetailService;

	@Autowired
	SysConfigService sysConfigService;

	@Override
	public PageUtils queryPage(Map<String, Object> params) {
		Page<MemberMachineEntity> page = this.selectPage(new Query<MemberMachineEntity>(params).getPage(),
				new EntityWrapper<MemberMachineEntity>().eq("member_id", params.get("userId")).in("status", (Integer[]) params.get("status")));

		return new PageUtils(page);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void buy(Long userId, Long machineId) {
		MachineEntity machine = machineService.selectById(machineId);
		Assert.notNull(machine, "矿机不存在");
		Assert.isTrue(machine.getStatus() == ProjectConstant.MACHINE_STATUS_ENABLE, "矿机已下架");
		MemberEntity member = memberService.selectById(userId);
		Assert.isTrue(member.getAuthStatus() == ProjectConstant.AUTH_STATUS_PASSED, "账号未实名认证");
		if (StringUtils.isBlank(member.getAlipay()) && StringUtils.isBlank(member.getWechat()) && StringUtils.isBlank(member.getBankCardNumber())) {
			throw new RRException("未设置收款信息");
		}
		Assert.isTrue(member.getBalance() >= machine.getPrice(), "您的余额不足");
		int personMaxMachine = sysConfigService.getValueI(ConfigConstant.PERSON_MAX_MACHINE);
		int totalMachine = this.selectCount(new EntityWrapper<MemberMachineEntity>().eq("member_id", userId).eq("status", ProjectConstant.MACHINE_RUNSTATUS_RUNNING));
		Assert.isTrue(totalMachine < personMaxMachine, "您的矿机已达到上限");
		
		// 速型矿机判断
		if (machine.getMachineType() == ProjectConstant.MACHINE_TYPE_FAST) {
			// 必须拥有一台正在运行的小型矿机
			totalMachine = this.selectCount(new EntityWrapper<MemberMachineEntity>()
					.eq("member_id", userId)
					.eq("status", ProjectConstant.MACHINE_RUNSTATUS_RUNNING)
					.in("machine_type",
							new Integer[] { ProjectConstant.MACHINE_TYPE_SMALL, ProjectConstant.MACHINE_TYPE_MIDSIZE, ProjectConstant.MACHINE_TYPE_LARGE,
									ProjectConstant.MACHINE_TYPE_HUGE }));
			Assert.isTrue(totalMachine > 0, "购买极速矿机必须拥有一台运行中的矿机,微型矿机除外");

			// 是否已拥有此矿机
			totalMachine = this.selectCount(new EntityWrapper<MemberMachineEntity>().eq("member_id", userId).eq("status", ProjectConstant.MACHINE_RUNSTATUS_RUNNING)
					.eq("machine_type", ProjectConstant.MACHINE_TYPE_FAST));
			Assert.isTrue(totalMachine == 0, "您已拥有极速矿机,请运行结束后再购买");
		}

		Date now = new Date();

		// 判断库存
		if (machine.getStock() != -1) {
			Assert.isTrue(machine.getStock() > 0, "矿机库存不足");
			machine.setStock(machine.getStock() - 1);
			machine.setUpdateTime(now);
			machineService.updateById(machine);
		}

		// 扣减余额
		member.setBalance(DecimalUtils.sub(member.getBalance(), machine.getPrice()));
		member.setUpdateTime(now);
		memberService.updateById(member);

		// 资金明细
		BalanceDetailEntity bd = new BalanceDetailEntity();
		bd.setMemberId(userId);
		bd.setBalanceChange(DecimalUtils.sub(0d, machine.getPrice()));
		bd.setCategory(2);// 买入矿机算收益类型
		bd.setCreateTime(now);
		balanceDetailService.insert(bd);

		// 插入矿机
		MemberMachineEntity mm = new MemberMachineEntity();
		mm.setMemberId(userId);
		mm.setMachineNo("M" + DateUtils.format(new Date(), "yyyyMMddHH") + RandomStringUtils.randomNumeric(5));
		mm.setMachineName(machine.getMachineName());
		mm.setMachineType(machine.getMachineType());
		mm.setPrice(machine.getPrice());
		mm.setHashSecond(machine.getHashSecond());
		mm.setTotalDays(machine.getTotalDays());
		mm.setTotalProfit(machine.getTotalProfit());
		mm.setDayProfit(machine.getDayProfit());
		mm.setRunningDays(0);
		mm.setSumProfit(0d);
		mm.setPreProfit(0d);
		mm.setStatus(ProjectConstant.MACHINE_RUNSTATUS_RUNNING);
		mm.setIsReward(ProjectConstant.COMMON_NO);
		mm.setCreateTime(now);
		mm.setMachineImg(machine.getMachineImg());
		this.insert(mm);

		// 计算矿工等级
		memberService.calcUserLevel(userId);

	}

	@Override
	public Double totalHashSecond(Long id) {
		return baseMapper.totalHashSecond(id);
	}

	@Override
	public Double totalPerDayProfit(Long id) {
		return baseMapper.totalPerDayProfit(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void getProfit(Long userId, Long mmId) {
		Assert.notNull(mmId, "ID为空");
		MemberMachineEntity mm = this.selectById(mmId);
		Assert.notNull(mm, "矿机不存在");
		Assert.isTrue(userId.equals(mm.getMemberId()), "此矿机不属于您");
		Assert.isTrue(mm.getPreProfit() > 0, "暂无可领取收益");

		Date now = new Date();
		// 会员余额更新
		MemberEntity member = memberService.selectById(userId);
		member.setBalance(DecimalUtils.add(member.getBalance(), mm.getPreProfit()));
		member.setUpdateTime(now);
		memberService.updateById(member);

		// 插入资金流水
		BalanceDetailEntity bd = new BalanceDetailEntity();
		bd.setMemberId(userId);
		bd.setBalanceChange(mm.getPreProfit());
		bd.setCategory(2);// 矿机收益
		bd.setCreateTime(now);
		balanceDetailService.insert(bd);

		// 待收益更新
		mm.setSumProfit(DecimalUtils.add(mm.getSumProfit(), mm.getPreProfit()));
		mm.setPreProfit(0d);
		mm.setUpdateTime(now);
		this.updateById(mm);
	}

}
